﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace RevClinic.Core.Domain
{
    public abstract class Entity<TId> : IEquatable<Entity<TId>>
    {
        public virtual TId Id { get; protected set; }

        private static readonly int HASH_MULTIPLIER = 31;

        public Entity() { }

        public Entity(TId id)
        {
            Id = id;
        }

        /// <summary>
        /// Transient entity is not persited, that means its id is null or default one
        /// </summary>
        /// <returns>true if entity is not persisted</returns>
        public virtual bool IsTransient()
        {
            return Id == null || Id.Equals(default(TId));
        }

        public override bool Equals(object obj)
        {
            Entity<TId> other = obj as Entity<TId>;
            return Equals(other);
        }

        /// <summary>
        /// Calculate equality to given entity of same type.
        /// </summary>
        /// <param name="other">entity to calculate equality</param>
        /// <returns>
        /// true when references are equal or both are persisted and have same id
        /// false when other is null or both are not persisted with same id
        /// </returns>
        public virtual bool Equals(Entity<TId> other)
        {
            if (other == null) {
                return false;
            }
            if (ReferenceEquals(this, other)) {
                return true;
            }
            return !IsTransient() && !other.IsTransient() && Id.Equals(other.Id);
        }

        private int? cachedHashCode;

        public override int GetHashCode()
        {
            if (!cachedHashCode.HasValue) {
                if (IsTransient()) {
                    cachedHashCode = base.GetHashCode();
                } else {
                    unchecked {
                        int hashBase = GetType().GetHashCode();
                        cachedHashCode = (hashBase * HASH_MULTIPLIER) ^ Id.GetHashCode();
                    }
                }
            }
            return cachedHashCode.Value;
        }
    }
}
